﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TechnicalAnalysisEngine;
using TechnicalAnalysisEngine.Tests;
using System.Diagnostics;

namespace TechnicalLibrary.Tests
{
    [TestClass]
    public class TestATR
    {
        List<double> inputHighs;
        List<double> inputLows;
        List<double> inputCloses;
        List<double> expectedValues;

        int expectedOffset;
        int expectedResultCount;
        int periods;

        [TestInitialize]
        public void Initialize()
        {
            inputHighs = new List<double>()
            {
                48.70,48.72,48.90,48.87,48.82,49.05,49.20,49.35,49.92,50.19,50.12,49.66,
                49.88,50.19,50.36,50.57,50.65,50.43,49.63,50.33,50.29,50.17,49.32,48.50,
                48.32,46.80,47.80,48.39,48.66,48.79
            };

            inputLows = new List<double>()
            {
                47.79,48.14,48.39,48.37,48.24,48.64,48.94,48.86,49.50,49.87,49.20,48.90,
                49.43,49.73,49.26,50.09,50.30,49.21,48.98,49.61,49.20,49.43,48.08,47.64,
                41.55,44.28,47.31,47.20,47.90,47.73
            };

            inputCloses = new List<double>()
            {
                48.16,48.61,48.75,48.63,48.74,49.03,49.07,49.32,49.91,50.13,49.53,49.50,
                49.75,50.03,50.31,50.52,50.41,49.34,49.37,50.23,49.24,49.93,48.43,48.18,
                46.57,45.41,47.77,47.72,48.62,47.85

            };

            expectedValues = new List<double>()
            {
               0.5550,0.5939,0.5858,0.5689,0.6155,0.6179,0.6424,0.6743,0.6928,0.7754,0.7815,1.2092,1.3026,1.3803,1.3667,1.3362,1.3165
            };

            expectedResultCount = 17;
            expectedOffset = 13;
            periods = 14;
        }

        [TestMethod]
        public void TestATRValues()
        {
            var result = AnalysisEngine.ATR(inputHighs, inputLows, inputCloses, periods);

            Assert.AreEqual(expectedOffset, result.StartIndexOffset, "Offsets do not match");
            Assert.AreEqual(expectedResultCount, result.Values.Count);

            string message = null;
            bool testResult = true;

            for (int i = 0; i < result.Values.Count; i++)
            {
                if (!TestHelpers.EqualsWithTolerance(result.Values[i], expectedValues[i], 1)) // 1% tolerance from expected results
                {
                    message = string.Format("Values do not match at position {0}, expected: {1}, actual: {2} ",
                        i, expectedValues[i], result.Values[i]);

                    testResult = false;
                    break;
                }
            }

            Assert.IsTrue(testResult, message);
        }

        [TestMethod]
        public void TestATRPerformance()
        {
            Random random = new Random();
            var randomlyGeneratedHighs = new List<double>();
            var randomlyGeneratedLows = new List<double>();
            var randomlyGeneratedCloses = new List<double>();

            for (int i = 0; i < 10000; i++)
            {
                randomlyGeneratedHighs.Add(random.Next(85, 90));
                randomlyGeneratedLows.Add(random.Next(80, 85));
                randomlyGeneratedCloses.Add(random.Next(83, 87));
            }

            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();

            AnalysisEngine.ATR(randomlyGeneratedHighs, randomlyGeneratedLows, randomlyGeneratedCloses, periods);

            stopWatch.Stop();
            Console.WriteLine(string.Format("ATR, {0} values, {1} μs", randomlyGeneratedHighs.Count, stopWatch.ElapsedTicks / 10));
        }
    }
}
